summaryrefslogtreecommitdiff
path: root/app/[lng]
diff options
context:
space:
mode:
Diffstat (limited to 'app/[lng]')
-rw-r--r--app/[lng]/evcp/(evcp)/b-rfq/[id]/final/page.tsx0
-rw-r--r--app/[lng]/evcp/(evcp)/b-rfq/[id]/initial/page.tsx0
-rw-r--r--app/[lng]/evcp/(evcp)/b-rfq/[id]/layout.tsx88
-rw-r--r--app/[lng]/evcp/(evcp)/b-rfq/[id]/page.tsx54
-rw-r--r--app/[lng]/evcp/(evcp)/b-rfq/page.tsx78
-rw-r--r--app/[lng]/partners/(partners)/document-list/[contractId]/page.tsx2
-rw-r--r--app/[lng]/partners/ocr/layout.tsx17
-rw-r--r--app/[lng]/partners/ocr/page.tsx6
8 files changed, 241 insertions, 4 deletions
diff --git a/app/[lng]/evcp/(evcp)/b-rfq/[id]/final/page.tsx b/app/[lng]/evcp/(evcp)/b-rfq/[id]/final/page.tsx
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/app/[lng]/evcp/(evcp)/b-rfq/[id]/final/page.tsx
diff --git a/app/[lng]/evcp/(evcp)/b-rfq/[id]/initial/page.tsx b/app/[lng]/evcp/(evcp)/b-rfq/[id]/initial/page.tsx
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/app/[lng]/evcp/(evcp)/b-rfq/[id]/initial/page.tsx
diff --git a/app/[lng]/evcp/(evcp)/b-rfq/[id]/layout.tsx b/app/[lng]/evcp/(evcp)/b-rfq/[id]/layout.tsx
new file mode 100644
index 00000000..75ce5ee5
--- /dev/null
+++ b/app/[lng]/evcp/(evcp)/b-rfq/[id]/layout.tsx
@@ -0,0 +1,88 @@
+import { Metadata } from "next"
+import Link from "next/link"
+import { Separator } from "@/components/ui/separator"
+import { SidebarNav } from "@/components/layout/sidebar-nav"
+import { RfqViewWithItems } from "@/db/schema/rfq"
+import { formatDate } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+import { ArrowLeft } from "lucide-react"
+import { RfqDashboardView } from "@/db/schema"
+import { findBRfqById } from "@/lib/b-rfq/service"
+
+export const metadata: Metadata = {
+ title: "견적 RFQ 상세",
+}
+
+export default async function RfqLayout({
+ children,
+ params,
+}: {
+ children: React.ReactNode
+ params: { lng: string, id: string }
+}) {
+
+ // 1) URL 파라미터에서 id 추출, Number로 변환
+ const resolvedParams = await params
+ const lng = resolvedParams.lng
+ const id = resolvedParams.id
+
+ const idAsNumber = Number(id)
+ // 2) DB에서 해당 협력업체 정보 조회
+ const rfq: RfqDashboardView | null = await findBRfqById(idAsNumber)
+
+ // 3) 사이드바 메뉴
+ const sidebarNavItems = [
+ {
+ title: "견적/입찰 문서관리",
+ href: `/${lng}/evcp/b-rfq/${id}`,
+ },
+ {
+ title: "Initial RFQ 발송",
+ href: `/${lng}/evcp/b-rfq/${id}/initial`,
+ },
+ {
+ title: "Final RFQ 발송",
+ href: `/${lng}/evcp/b-rfq/${id}/final`,
+ },
+
+ ]
+
+ return (
+ <>
+ <div className="container py-6">
+ <section className="overflow-hidden rounded-[0.5rem] border bg-background shadow">
+ <div className="hidden space-y-6 p-10 pb-16 md:block">
+ <div className="flex items-center justify-end mb-4">
+ <Link href={`/${lng}/evcp/b-rfq`} passHref>
+ <Button variant="ghost" className="flex items-center text-primary hover:text-primary/80 transition-colors p-0 h-auto">
+ <ArrowLeft className="mr-1 h-4 w-4" />
+ <span>RFQ 목록으로 돌아가기</span>
+ </Button>
+ </Link>
+ </div>
+ <div className="space-y-0.5">
+ {/* 4) 협력업체 정보가 있으면 코드 + 이름 + "상세 정보" 표기 */}
+ <h2 className="text-2xl font-bold tracking-tight">
+ {rfq
+ ? `${rfq.rfqCode ?? ""} | ${rfq.packageNo ?? ""} | ${rfq.packageName ?? ""}`
+ : "Loading RFQ..."}
+ </h2>
+
+ <p className="text-muted-foreground">
+ PR발행 전 RFQ를 생성하여 관리하는 화면입니다.
+ </p>
+ <h3>Due Date:{rfq && rfq?.dueDate && <strong>{formatDate(rfq?.dueDate)}</strong>}</h3>
+ </div>
+ <Separator className="my-6" />
+ <div className="flex flex-col space-y-8 lg:flex-row lg:space-x-12 lg:space-y-0">
+ <aside className="lg:w-64 flex-shrink-0">
+ <SidebarNav items={sidebarNavItems} />
+ </aside>
+ <div className="lg:w-[calc(100%-16rem)] overflow-auto">{children}</div>
+ </div>
+ </div>
+ </section>
+ </div>
+ </>
+ )
+} \ No newline at end of file
diff --git a/app/[lng]/evcp/(evcp)/b-rfq/[id]/page.tsx b/app/[lng]/evcp/(evcp)/b-rfq/[id]/page.tsx
new file mode 100644
index 00000000..e8820af5
--- /dev/null
+++ b/app/[lng]/evcp/(evcp)/b-rfq/[id]/page.tsx
@@ -0,0 +1,54 @@
+import { Separator } from "@/components/ui/separator"
+import { type SearchParams } from "@/types/table"
+import { getValidFilters } from "@/lib/data-table"
+
+interface IndexPageProps {
+ // Next.js 13 App Router에서 기본으로 주어지는 객체들
+ params: {
+ lng: string
+ id: string
+ }
+ searchParams: Promise<SearchParams>
+}
+
+export default async function RfqPage(props: IndexPageProps) {
+ const resolvedParams = await props.params
+ const lng = resolvedParams.lng
+ const id = resolvedParams.id
+
+ const idAsNumber = Number(id)
+
+ console.log(idAsNumber)
+
+ // 2) SearchParams 파싱 (Zod)
+ // - "filters", "page", "perPage", "sort" 등 contact 전용 컬럼
+ const searchParams = await props.searchParams
+ // const search = searchParamsMatchedVCache.parse(searchParams)
+ // const validFilters = getValidFilters(search.filters)
+
+ // const promises = Promise.all([
+ // getMatchedVendors({
+ // ...search,
+ // filters: validFilters,
+ // },
+ // idAsNumber)
+ // ])
+
+ // 4) 렌더링
+ return (
+ <div className="space-y-6">
+ <div>
+ <h3 className="text-lg font-medium">
+ 견적 RFQ 문서관리
+ </h3>
+ <p className="text-sm text-muted-foreground">
+ 설계로부터 받은 RFQ 문서와 구매 RFQ 문서를 관리하고 Vendor 회신을 점검/관리하는 화면입니다.
+ </p>
+ </div>
+ <Separator />
+ <div>
+ {/* <MatchedVendorsTable promises={promises} rfqId={idAsNumber}/> */}
+ </div>
+ </div>
+ )
+} \ No newline at end of file
diff --git a/app/[lng]/evcp/(evcp)/b-rfq/page.tsx b/app/[lng]/evcp/(evcp)/b-rfq/page.tsx
new file mode 100644
index 00000000..213e9127
--- /dev/null
+++ b/app/[lng]/evcp/(evcp)/b-rfq/page.tsx
@@ -0,0 +1,78 @@
+import * as React from "react"
+import { Metadata } from "next"
+import { type SearchParams } from "@/types/table"
+import { getValidFilters } from "@/lib/data-table"
+import { Shell } from "@/components/shell"
+import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton"
+import { searchParamsRFQDashboardCache } from "@/lib/b-rfq/validations"
+import { getRFQDashboard } from "@/lib/b-rfq/service"
+import { RFQDashboardTable } from "@/lib/b-rfq/summary-table/summary-rfq-table"
+
+export const metadata: Metadata = {
+ title: "견적 RFQ",
+ description: "",
+}
+
+interface PQReviewPageProps {
+ searchParams: Promise<SearchParams>
+}
+
+export default async function PQReviewPage(props: PQReviewPageProps) {
+ const searchParams = await props.searchParams
+ const search = searchParamsRFQDashboardCache.parse(searchParams)
+ const validFilters = getValidFilters(search.filters)
+
+ // 기본 필터 처리 (통일된 이름 사용)
+ let basicFilters = []
+ if (search.basicFilters && search.basicFilters.length > 0) {
+ basicFilters = search.basicFilters
+ console.log("Using search.basicFilters:", basicFilters);
+ } else {
+ console.log("No basic filters found");
+ }
+
+ // 모든 필터를 합쳐서 처리
+ const allFilters = [...validFilters, ...basicFilters]
+
+ // 조인 연산자도 통일된 이름 사용
+ const joinOperator = search.basicJoinOperator || search.joinOperator || 'and';
+
+ // Promise.all로 감싸서 전달
+ const promises = Promise.all([
+ getRFQDashboard({
+ ...search,
+ filters: allFilters,
+ joinOperator,
+ })
+ ])
+
+ return (
+ <Shell className="gap-4">
+ <div className="flex items-center justify-between space-y-2">
+ <div className="flex items-center justify-between space-y-2">
+ <div>
+ <h2 className="text-2xl font-bold tracking-tight">
+ 견적 RFQ
+ </h2>
+ </div>
+ </div>
+ </div>
+
+ {/* Items처럼 직접 테이블 렌더링 */}
+ <React.Suspense
+ key={JSON.stringify(searchParams)} // URL 파라미터가 변경될 때마다 강제 리렌더링
+ fallback={
+ <DataTableSkeleton
+ columnCount={8}
+ searchableColumnCount={2}
+ filterableColumnCount={3}
+ cellWidths={["10rem", "15rem", "12rem", "12rem", "8rem", "8rem", "10rem", "8rem"]}
+ shrinkZero
+ />
+ }
+ >
+ <RFQDashboardTable promises={promises} />
+ </React.Suspense>
+ </Shell>
+ )
+} \ No newline at end of file
diff --git a/app/[lng]/partners/(partners)/document-list/[contractId]/page.tsx b/app/[lng]/partners/(partners)/document-list/[contractId]/page.tsx
index 80621682..ef0778aa 100644
--- a/app/[lng]/partners/(partners)/document-list/[contractId]/page.tsx
+++ b/app/[lng]/partners/(partners)/document-list/[contractId]/page.tsx
@@ -39,7 +39,7 @@ export default async function DocumentListPage(props: IndexPageProps) {
return (
<div className="space-y-6">
<div>
- <EnhancedDocumentsTable promises={promises} selectedPackageId={idAsNumber} projectType={projectType}/>
+ <EnhancedDocumentsTable contractId={idAsNumber} promises={promises} selectedPackageId={idAsNumber} projectType={projectType}/>
</div>
</div>
)
diff --git a/app/[lng]/partners/ocr/layout.tsx b/app/[lng]/partners/ocr/layout.tsx
new file mode 100644
index 00000000..f1654bf2
--- /dev/null
+++ b/app/[lng]/partners/ocr/layout.tsx
@@ -0,0 +1,17 @@
+import { ReactNode } from 'react';
+import { SiteFooter } from '@/components/layout/Footer';
+import { HeaderSimple } from '@/components/layout/HeaderSimple';
+
+export default function EvcpLayout({ children }: { children: ReactNode }) {
+ return (
+ <div className="relative flex min-h-svh flex-col bg-background">
+ <HeaderSimple />
+ <main className="flex flex-1 flex-col">
+ <div className='container-wrapper'>
+ {children}
+ </div>
+ </main>
+ <SiteFooter/>
+ </div>
+ );
+} \ No newline at end of file
diff --git a/app/[lng]/partners/ocr/page.tsx b/app/[lng]/partners/ocr/page.tsx
index b75df420..7a12b75d 100644
--- a/app/[lng]/partners/ocr/page.tsx
+++ b/app/[lng]/partners/ocr/page.tsx
@@ -72,7 +72,7 @@ export default async function IndexPage(props: IndexPageProps) {
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold tracking-tight">
- RFQ
+ Welding OCR
</h2>
</div>
</div>
@@ -102,10 +102,10 @@ export default async function IndexPage(props: IndexPageProps) {
<div className="flex items-center justify-between space-y-2">
<div>
<h2 className="text-2xl font-bold tracking-tight">
- RFQ
+ Welding OCR
</h2>
<p className="text-muted-foreground">
- RFQ를 응답하고 커뮤니케이션을 할 수 있습니다.
+ PDF 파일을 업로드하면 테이블에 값이 삽입됩니다.
</p>
</div>
</div>